#ifndef SHIJU_BBU_MAMANGER_H_INCLUDE
#define SHIJU_BBU_MAMANGER_H_INCLUDE

#include <set>
#include "NmmToX86Protocol.h"
#include "OamMessageProtocol.h"
#include "eutranManager.h"
#include "MessageDef.h"
#include "EutranTcpReceiver.h"

#define BandDataPtr (BandData::instance())
#define BbuManagerPtr (BbuManager::instance())

enum LteDuplexMode
{
    TDD = 0,
    FDD = 1,
    NUM_OF_LTE_DUPLEX_MODE
};

enum ChinaTelecomOperator
{
    CHINA_MOBILE = 0,
    CHINA_TELECOM = 1,
    CHINA_UNICOM = 2,
    NUM_OF_CHINA_TELE_OPER
};

class BandData
{
public:
    static BandData* instance();
    static bool getArfcnRangeFromBand(uint8_t band, uint16_t& lowerArfcn, uint16_t& upperArfcn);

    inline static uint8_t getBandFromEarfcn(uint16_t earfcn)
    {
        return bandTable_[earfcn];
    }
private:
    BandData();
    BandData(const BandData&);
    BandData& operator=(const BandData&);

    static uint8_t bandTable_[65536];
};
/*
class BandCap
{
public:
    static const uint32_t BAND9 = 0x0001;
    static const uint32_t BAND38 = 0x0002;
    static const uint32_t BAND39 = 0x0004;
    static const uint32_t BAND40 = 0x0008;
    static const uint32_t MIN_BAND_MASK = BAND9;
    static const uint32_t MAX_BAND_MASK = BAND40;

    BandCap(uint32_t mask);
    bool isSupported(uint32_t mask);
    void addBand(uint8_t band);

    inline static uint32_t getBandMaskCodeFromEarfcn(uint16_t earfcn)
    {
        if( bandTable_[earfcn]==9 )
        {
            return BAND9;
        }
        else if( bandTable_[earfcn]==38 )
        {
            return BAND38;
        }
        else if( bandTable_[earfcn]==39 )
        {
            return BAND39;
        }
        else if( bandTable_[earfcn]==40 )
        {
            return BAND40;
        }
        return 0;
    }
    
    inline bool operator==(const BandCap& other)
    {
        if( this->capacities_==other.capacities_ )
        {
            return true;
        }
        return false;
    }

    inline uint32_t getCapacity()
    {
        return capacities_;
    }
private:
    uint32_t capacities_; 
    
};*/


class BbuInstance
{
public:
    uint32_t getSlotId();
    BbuInstance& setSlotId(uint8_t slotId);

    BbuInstance& setPeerAddress(const char* addr, uint16_t port);
    
    LteDuplexMode getDuplexMode();
    BbuInstance& setDuplexMode(LteDuplexMode);
    
    ChinaTelecomOperator getTeleOperator();
    BbuInstance& setTeleOperator(ChinaTelecomOperator);
    
    bool IsBandSupported(uint8_t);
    BbuInstance& addBandSupported(uint8_t);
    void getSupportedBands(std::set<uint8_t>& bands);

    bool isHearBeatAckRev();
    BbuInstance& setHearBeatAckRecv(bool isRecv);
    
    uint32_t getBbuIpAddress();
    bool isActive();

    bool active();
    void deactive();

    void changTeleOperator(int32_t OperatorType);

    virtual bool sendMessage(uint8_t* msgBuf, uint32_t msgSize);
    bool sendMessage(TlvMessage&);

    uint32_t allocSeqNo();

    BbuStateCode getState();
    BbuInstance& setState(BbuStateCode state);
protected:
    
    friend class BbuCtrl;
    friend class BbuManager;
    BbuInstance(const char* address, uint16_t slotId) throw (std::exception);
    BbuInstance();
    BbuInstance(const BbuInstance&);
    BbuInstance& operator=(const BbuInstance&);

    enum state
    {
        INVALID = 0,
        INIT_CFG = 1,
        ACTIVE = 2
    };
    
    int32_t fd_;
    uint8_t slotId_;
    bool isActive_;
    bool isHearbeatRecv_;
    struct sockaddr_in peerAddr_;
    
    LteDuplexMode supportMode_;
    ChinaTelecomOperator operator_;
    std::set<uint8_t> bandSupported_;
    uint32_t seqNo_;
    BbuStateCode stateCode_;
};

class BbuInstanceWithTcp : public BbuInstance
{
public:
    virtual bool sendMessage(uint8_t* msgBuf, uint32_t msgSize);
    bool sendMessage(TlvMessage&);
private:
};

class BbuCtrl
{
public:

    void processInitNotification2(NmmToX86Protocol_InitNotification& initNoti);
    void processHBAck(NmmToX86Protocol_HeartBeatAck& ack);
    bool sendRtParaCfg(OamMessageProtocol_RunTimeParaCfg& cfg);
    bool buildAndSendUeIdFilter(bool enable, uint32_t* timer);
    bool buildAndSendStdTxPowerDbGet();
    bool buildAndSendStdTxPowerGet();
    bool buildAndSendStdTxPower(uint8_t txPwer);
    bool buildAndSendInitCfg();
    bool buildAndSendSnifferReset();
    bool buildAndSendTimeSync();
    bool buildAndSendSnifferStatusReq();
    bool buildAndSendSysTimeSync();
    bool buildAndSendTxPowerDb(int8_t txPwer);
    bool buildAndSendRxPower(uint8_t rxPwer);
    bool buildAndSendSoftwareVerReq();
    bool buildAndSendBbuStateReq();
    bool buildAndSendRebootReq(std::string& desc);
    bool buildAndSendSyncModeSetting(uint8_t modeCode);
    bool buildAndSendSyncStateReq();
    bool buildAndSendGpsStateReq();
    bool buildAndSendUpgradeReq(std::string& ipAddr, std::string& fileName, std::string& md5, std::string& userName, std::string& passwd, uint8_t downMode);
    bool buidlAndSendLocModeSetting(bool isEnable, std::vector<std::string>& imsiList);
    bool buildAndSendUeRedire(bool isEnable, uint8_t* ranType, uint8_t* band, std::vector<uint16_t>* arfcnList, std::vector<std::string>* imsiList);
    bool buildAndSendScanReq();
    bool buildAndSendInterferenceEnable(bool isEnable);
    bool buildAndSendMinRxLev();

    BbuInstance& getInstance();
	bool buildAndSendScanMode(std::vector<uint16_t>& dlArfcnList, uint32_t sec);
    BbuCtrl& connEstablish();
    BbuCtrl& setInitCfgComp(bool);
    BbuCtrl& setWorking(bool);
    uint16_t getWorkingDlArfcn();
    uint16_t getWorkingUlArfcn();
    uint16_t getWorkingPci();
    uint16_t getWorkingTac();
    void setWorkingDlArfcn(uint16_t dlArfcn);
    std::vector<uint32_t>& getWorkingPlmnList();
    bool getTxPower(int16_t&);
    bool getWorkingMeasEnable();

    BbuCtrl& setLocationEnable(bool isEnable);
    BbuCtrl& setWorkingUlArfcn(uint16_t ulArfcn);
    BbuCtrl& setWorkingCellInfo(uint16_t dlArfcn, uint16_t ulArfcn, uint16_t pci, uint16_t tac, 
                                                         const std::vector<uint32_t>& plmn, int16_t* txPwerPtr, bool isMeasEnable);

    bool isLocationEnable();
    bool isInitCfgComplete();
    bool isWorking();
    void indicateDeactive(bool isCloseConn=true);
    void indicateAactive();

    void registerBbu(uint8_t slotId);
    bool BbuIsRegisted();

    void setRecvImsi(bool isRecv);
    bool isRecvImsi();

	void setSnifferArfcn(std::vector<uint16_t>& arfcnRange);
	std::vector<uint16_t>& getSnifferArfcn();
	void setWorkingPlmnList(std::vector<uint32_t> &plmnList);

    void handleCtrlPA(bool isOpening, uint8_t ctrlType);

    uint8_t getPaId();

    void handleCtrlPaResult(bool isOn);

    enum ctrlPaType
    {
        DO_NOTHING = 0,
        POWER_RESET = 1,
        REBOOT = 2

    };

private:
    friend class BbuManager;
    BbuCtrl();
    BbuCtrl(const BbuCtrl&);
    BbuCtrl& operator=(const BbuCtrl&);

    uint32_t pwerResetTimer_;
    EutranTimerElement<BbuCtrl> pwerResetHandler_;
    void powerReset();

    uint32_t pwerResetTimeoutTimer_;
    EutranTimerElement<BbuCtrl> pwerResetTimeoutHandler_;
    void pwerResetTimeout();

    uint32_t maxPwerResetNum_;

#ifdef USE_TCP_CONN
    BbuInstanceWithTcp instanceData_;
#else
    BbuInstance instanceData_;
#endif
    bool isInitCfgComp_;
    bool isWorking_;
    bool isLocationEnable_;
    
    bool isRegistered_;
    bool isRecvImsi_;



    bool paIsOn_;
    bool paIsOpening_;
    uint8_t paHandleType_;
    uint32_t paCtrlTimer_;
    EutranTimerElement<BbuCtrl> paCtrlTimeoutHandler_;
    void paCtrlTimeout();

    uint32_t maxPaCtrlNum_;


    uint16_t workingDlArfcn_;
    uint16_t workingUlArfcn_;
    uint16_t workingPci_;
    uint16_t workingTac_;
    std::vector<uint32_t> workingPlmnList_;
	std::vector<uint16_t> snfArfcn_;
    bool isWorkingMeasEnable_;

    bool isTxPwerPresent_;
    int16_t txPwer_;
};

class BbuManager
{
public:
    static const uint32_t MAX_BBU_INSTANCES = 7;

    static BbuManager* instance();
    bool initialize();

    BbuCtrl* getBbu(uint8_t slotId);
    BbuCtrl* getBbu(in_addr_t addr);
    BbuCtrl* getBbu(uint8_t band, ChinaTelecomOperator oper);
    void getIdOfActiveBbus(std::set<uint32_t>& ids);
    uint32_t getNoOfActivateBbu();
    bool isSlotIdValid(uint8_t slotId);


    void setLocationImsi(std::vector<std::string>& imsi);
    void getLocationImsi(std::vector<std::string>& imsi);
	void setLocationEnable(LteDuplexMode mode, bool enable);
	bool getLocationEnable(LteDuplexMode mode);

	bool isLocationMode();
	void setLocationMode(bool isLocationMode);
    void reportBbuLost(uint8_t slotId);

       
private:
    BbuManager();
    BbuManager(const BbuManager&);
    BbuManager& operator=(const BbuManager&);

    uint32_t sendHBTimer_; 
    EutranTimerElement<BbuManager> sendHBHandler_;
    void sendHearBeat();

    uint32_t checkBbuAliveTimer_;
    EutranTimerElement<BbuManager> checkBbuAliveHandler_;
    void checkBbuAlive();

    void reportCannotRecvImsi(uint8_t slotId);
    uint32_t checkRecvImsiTimer_;
    EutranTimerElement<BbuManager> checkRecvImsiHandler_;
    void checkRecvImsi();    


	std::vector<std::string> locaionTargetImsi_;
	bool locationEnable[NUM_OF_LTE_DUPLEX_MODE];
    BbuCtrl bbuCtrls_[MAX_BBU_INSTANCES];

	bool isLocationMode_;
};
#endif
